Add optional Claude Code hook for blocking malicious packages#168
Add optional Claude Code hook for blocking malicious packages#168David Larsen (dc-larsen) wants to merge 3 commits intomainfrom
Conversation
Adds a PreToolUse hook (socket-gate.ts) that intercepts npm/yarn/bun/pnpm install commands and checks packages against the Socket API. Blocks packages with critical or high severity alerts (typosquats, malware, supply chain attacks). Fails open on all errors. Includes tests and README documentation.
Uses 'socket package score' instead of calling the /v0/purl endpoint directly. Auth is handled by the CLI's own config (socket login), so no SOCKET_API_KEY env var is required.
| |----------------|----------|---------| | ||
| | **Critical** | Block installation | `browserlist` (typosquat of `browserslist`) | | ||
| | **High** | Block installation | Packages with known supply chain risks | | ||
| | **Low/None** | Allow | `express`, `lodash`, `react` | |
There was a problem hiding this comment.
| | **Low/None** | Allow | `express`, `lodash`, `react` | | |
| | **Medium/Low** | Allow | `express`, `lodash`, `react` | |
No such thing as "None" severity
There was a problem hiding this comment.
Addressed in f5a8127. We rewrote the table around supply chain score bands rather than alert severity, so the Low/None row is gone.
André Staltz (staltz)
left a comment
There was a problem hiding this comment.
I'm not sure if this hook will catch all the package installs. For example, what if Claude wrote new packages in the package.json and then ran npm install in bash? It wouldn't detect any new package in that case.
I don't know what's the best way of hooking in that case, because we don't know exactly what package was added, but I just want to leave this here. Perhaps this warrants a little warning in the README.md so users know how safe/unsafe this hook is.
|
|
||
| if (!isSocketInstalled()) { | ||
| // CLI not installed, fail open | ||
| outputAllow() |
There was a problem hiding this comment.
I think if users installed this hook but forgot to install the CLI, they would like to be warned so they don't feel "safe" while in reality being totally exposed. So I'd use outputDeny here. It shouldn't be too disruptive because there's no reason to have the hook installed if you have no Socket CLI.
There was a problem hiding this comment.
Good call. Dropped the Socket CLI entirely in f5a8127 and went back to calling /v0/purl directly with SOCKET_API_KEY. Applied the same fail-closed philosophy to the missing-key case: if SOCKET_API_KEY isn't set, the hook denies with a setup message instead of silently allowing.
- Drop Socket CLI dependency; call /v0/purl directly with SOCKET_API_KEY - Block when score.supplyChain < 0.2 (typosquats, known malware) - Deny when SOCKET_API_KEY is missing so users are not silently unprotected - Fail open on network, parse, and timeout errors - Add limitations section to README (manifest-edit gap, JS-only scope) - Update tests to match new API-based flow
|
André Staltz (@staltz) addressed the coverage gap in f5a8127 — added a Limitations section to the README that calls out the manifest-edit + bare-install case explicitly, along with JS-only scope, direct downloads, and transitive/post-install gaps. Also points readers at the MCP server + Socket Firewall for defense in depth. Other changes in the same commit:
|
|
Superseded by #172, which uses the public Socket MCP server at https://mcp.socket.dev/ (no API key, no CLI required) and adds support for PyPI, Cargo, RubyGems, Go, and NuGet in addition to npm. |
Summary
Adds a
PreToolUsehook (hooks/socket-gate.ts) for Claude Code that intercepts package install commands and checks them against the Socket API before allowing installation.browserlist, malware)SOCKET_API_KEYenv var as the MCP server--experimental-strip-types)Files
hooks/socket-gate.tshooks/socket-gate.test.tsREADME.mdHow it works
The hook reads Claude Code's
PreToolUsestdin payload, extracts the package name from install commands (npm install,yarn add,bun add,pnpm add), calls the Socket/v0/purlendpoint withalerts=true, and returnsdenyif critical/high alerts are found.Test results
Inspired by Jimmy Vo's blog post.